package com.iteaj.iot.client.udp;

import com.iteaj.iot.client.ClientComponent;
import com.iteaj.iot.client.ClientRequestProtocol;
import com.iteaj.iot.client.IotNettyClient;
import com.iteaj.network.ProtocolException;
import com.iteaj.network.client.ClientMessage;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.InetSocketAddress;

public abstract class UdpNettyClient extends IotNettyClient {

    public UdpNettyClient(UdpClientComponent clientComponent) {
        super(clientComponent);
    }

    @Override
    public void init(NioEventLoopGroup clientGroup) {
        super.init(clientGroup);
    }

    @Override
    protected Bootstrap doInit(Bootstrap bootstrap) {
        bootstrap.channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true);
        return bootstrap;
    }

    @Override
    protected ChannelHandler channelHandler() {
        return new ChannelInitializer<NioDatagramChannel>() {

            @Override
            protected void initChannel(NioDatagramChannel ch) throws Exception {
                setChannel(ch);
                UdpNettyClient.this.doInitChannel(ch);
            }
        };
    }

    @Override
    public void doConnect() {
        getBootstrap().bind(0).addListener(future -> {
            connectLogger((ChannelFuture) future);
        });
    }

    @Override
    public void doConnect(long timeout) throws ProtocolException {
        /*doing nothing*/
    }

    @Override
    protected abstract DatagramPacketToMessageDecoder initClientRequestDecoder();

    /**
     * 写出的报文必须是 UdpRequestProtocol 协议类型
     * @param clientRequestProtocol
     * @return
     */
    @Override
    public ChannelFuture writeAndFlush(ClientRequestProtocol clientRequestProtocol) {
        // 写入Udp报文 DatagramPacket
        if(clientRequestProtocol instanceof UdpRequestProtocol) {
            final ClientMessage clientMessage = clientRequestProtocol.requestMessage();

            final ByteBuf byteBuf = Unpooled.wrappedBuffer(clientMessage.getMessage());
            final DatagramPacket packet = new DatagramPacket(byteBuf, new InetSocketAddress(getHost(), getPort()));
            ((UdpRequestProtocol) clientRequestProtocol).setPacket(packet);
        } else {
            throw new ProtocolException("Udp客户端只支持写出协议类型["+UdpRequestProtocol.class.getSimpleName()+"]");
        }

        return super.writeAndFlush(clientRequestProtocol);
    }
}
